using System;
using System.Collections;
using System.Text;

namespace ObjectLib
{
    /// <summary>
    /// This is an overriden version of ArrayList that works with PolygonF objects.
    /// A sorted order is maintained for fast searching and list comparison operations.
    /// </summary>
    [Serializable]
    public class PathFarray : ArrayList
    {
        public bool AutoSort = false;
        public new PathF this[int index]
        {
            get
            {
                return ((PathF)base[index]);
            }
            set
            {
                if (AutoSort)
                    InsertSorted(value);
                else
                    base[index] = value;
            }
        }
        public override int Add(object value)
        {
            if (AutoSort)
            {
                for (int i = 0; i < this.Count; i++)
                    if (this[i].CompareTo(value) >= 0)
                    {
                        base.Insert(i, value);
                        return i;
                    }
            }
            return base.Add(value);
        }
        public override void AddRange(ICollection c)
        {
            base.AddRange(c);
            if (AutoSort)
                this.Sort();
        }
        public override void Insert(int index, object value)
        {
            InsertSorted((PathF)value);
        }
        public override void InsertRange(int index, ICollection c)
        {
            base.AddRange(c);
            if (AutoSort)
                this.Sort();
        }
        public void InsertSorted(PathF obj)
        {
            for (int i = 0; i < this.Count; i++)
            {
                if (obj.CompareTo(this[i]) < 1)
                {
                    base.Insert(i, obj);
                    return;
                }
            }
            base.Add(obj);
        }
        public override void Remove(object obj)
        {
            base.Remove(obj);
        }
        public override void RemoveRange(int index, int count)
        {
            base.RemoveRange(index, count);
        }
        public override bool Contains(object item)
        {
            if (AutoSort)
                return BinarySearch(item) >= 0;
            return base.Contains(item);
        }
        public override int IndexOf(object value)
        {
            if (AutoSort)
                return BinarySearch(value);
            return base.IndexOf(value);
        }
        public override int IndexOf(object value, int startIndex)
        {
            if (AutoSort)
                return BinarySearch(startIndex, this.Count - startIndex, value, null);
            return base.IndexOf(value, startIndex);
        }
        public override int IndexOf(object value, int startIndex, int count)
        {
            if (AutoSort)
                return BinarySearch(startIndex, count, value, null);
            return base.IndexOf(value, startIndex, count);
        }
        /// <summary>
        /// Returns -1 if point not contained, otherwise returns the index of the polygon containing the point.
        /// </summary>
        /// <param name="xx"></param>
        /// <param name="yy"></param>
        /// <returns></returns>
        public virtual void PolygonsContainingPoint(float xx, float yy, PolygonFlist output)
        {
            object o;
            for (int i = 0; i < this.Count; i++)
            {
                o = this[i];
                if (o.GetType() == typeof(PolygonF) && ((PolygonF)o).Pix.PixelIsTagged((int)(xx + 0.5f), (int)(yy + 0.5)))
                    output.Add((PolygonF)o);
            }
        }
        /// <summary>
        /// True if a PolygonF in this list contains the given point, false otherwise.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public virtual bool ContainsPoint(float x, float y)
        {
            object o;
            for (int i = 0; i < this.Count; i++)
            {
                o = this[i];
                if (o.GetType() == typeof(PolygonF) && ((PolygonF)o).InPoly(x, y) > 0)
                    return true;
            }
            return false;
        }
        public virtual bool ContainsPoint(int x, int y)
        {
            return ContainsPoint((float)x + 0.5f, (float)y + 0.5f);
        }
        /// <summary>
        /// Assumes lists have been sorted.
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public virtual bool ContentsAreEqualTo(PathFarray pflist)
        {
            //	see if the lists are the same size
            if (this.Count != pflist.Count)
                return false;
            int j;
            //	if they are the same size, compare each member.
            for (j = 0; j < pflist.Count; j++)
            {
                //	Lists are sorted, so sequential comparisons must all be true if lists are actually equal
                if (this[j] != pflist[j])
                    return false;
            }
            return true;
        }
        /// <summary>
        /// The Circumference of each PathF object in the list.
        /// </summary>
        public float[] EdgeLengths
        {
            get
            {
                float[] output = new float[this.Count];
                for (int i = 0; i < this.Count; i++)
                {
                    output[i] = this[i].Circumfrence;
                }
                return output;
            }
        }
        /// <summary>
        /// Creates a PathFarray from a PolygonFlist.
        /// </summary>
        /// <param name="list"></param>
        public PathFarray(bool AutoSort, PolygonFlist list)
        {
            for (int i = 0; i < list.Count; i++)
                this.Add(list[i]);
            this.AutoSort = AutoSort;
            if (AutoSort)
                this.Sort();
        }
        public PathFarray(bool AutoSort, int count)
            : base(count)
        {
            this.AutoSort = AutoSort;
        }
        /// <summary>
        /// Creates a PathFarray from a PolygonFarray.
        /// </summary>
        /// <param name="list"></param>
        public PathFarray(bool AutoSort, PolygonFarray list)
        {
            for (int i = 0; i < list.Count; i++)
                this.Add(list[i]);
            this.AutoSort = AutoSort;
            if (AutoSort)
                this.Sort();
        }
        public PathFarray(bool AutoSort)
            : base()
        {
            this.AutoSort = AutoSort;
        }
    }
    [Serializable]
    public class PolyFarray : PathFarray
    {
        public PolyFarray(bool AutoSort) : base(AutoSort) { }
        /// <summary>
        /// Creates a PolyFarray from a PolygonFlist.
        /// </summary>
        /// <param name="list"></param>
        public PolyFarray(bool AutoSort, PolygonFlist list) : base(AutoSort, list) { }
        public PolyFarray(bool AutoSort, int count) : base(AutoSort, count) { }
        /// <summary>
        /// Creates a PolyFarray from a PolygonFarray.
        /// </summary>
        /// <param name="list"></param>
        public PolyFarray(bool AutoSort, PolygonFarray list) : base(AutoSort, list) { }
        public new PolygonF this[int index]
        {
            get
            {
                return (PolygonF)base[index];
            }
            set
            {
                if (AutoSort)
                    InsertSorted(value);
                else
                    base[index] = value;
            }
        }
    }
    [Serializable]
    public class ContourFarray : PathFarray
    {
        public ContourFarray(bool AutoSort) : base(AutoSort) { }
        public new ContourF this[int index]
        {
            get
            {
                return ((ContourF)base[index]);
            }
            set
            {
                if (AutoSort)
                    InsertSorted(value);
                else
                    base[index] = value;
            }
        }
        /// <summary>
        /// Does nothing.
        /// </summary>
        /// <param name="xx"></param>
        /// <param name="yy"></param>
        /// <returns></returns>
        public override void PolygonsContainingPoint(float xx, float yy, PolygonFlist output)
        {
        }
        /// <summary>
        /// Returns false.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public override bool ContainsPoint(float x, float y)
        {
            return false;
        }
        /// <summary>
        /// Returns false.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public override bool ContainsPoint(int x, int y)
        {
            return false;
        }
    }
    /// <summary>
    /// This is an overriden version of ArrayList that works with PolygonF objects.
    /// A sorted order is maintained for fast searching and list comparison operations.
    /// </summary>
    [Serializable]
    public class PolygonFarray : ArrayList
    {
        [NonSerialized]
        public bool AutoSort;
        public PolygonFarray() : base()
        {
            this.AutoSort = true;
        }
        public PolygonFarray(bool AutoSort) : base()
        {
            this.AutoSort = AutoSort;
        }
        public new PolygonF this[int index]
        {
            get
            {
                return ((PolygonF)base[index]);
            }
            set
            {
                base[index] = value;
                if(AutoSort)
                    this.Sort();
            }
        }
        public override int Add(object value)
        {
            int result = base.Add(value);
            if(AutoSort)
                this.Sort();
            return result;
        }
        public override void AddRange(ICollection c)
        {
            base.AddRange(c);
            if(AutoSort)
                this.Sort();
        }
        public override void Insert(int index, object value)
        {
            base.Insert(index, value);
            if(AutoSort)
                this.Sort();
        }
        public override void InsertRange(int index, ICollection c)
        {
            base.InsertRange(index, c);
            if(AutoSort)
                this.Sort();
        }
        public override void Remove(object obj)
        {
            base.Remove(obj);
            if(AutoSort)
                this.Sort();
        }
        public override void RemoveRange(int index, int count)
        {
            base.RemoveRange(index, count);
            if(AutoSort)
                this.Sort();
        }
        /// <summary>
        /// Returns -1 if point not contained, otherwise returns the index of the polygon containing the point.
        /// </summary>
        /// <param name="xx"></param>
        /// <param name="yy"></param>
        /// <returns></returns>
        public void PolygonsContainingPoint(float xx, float yy, PolygonFlist output)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].Pix.PixelIsTagged((int)(xx + 0.5f), (int)(yy + 0.5)))
                    output.Add(this[i]);
        }
        public bool ContainsPoint(float x, float y)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].InPoly(x, y) > 0)
                    return true;
            return false;
        }
        public bool ContainsPoint(int x, int y)
        {
            return ContainsPoint((float)x + 0.5f, (float)y + 0.5f);
        }
        /// <summary>
        /// Assumes lists have been sorted.
        /// </summary>
        /// <param name="pf"></param>
        /// <returns></returns>
        public bool ContentsAreEqualTo(PolygonFarray pflist)
        {
            //	see if the lists are the same size
            if (this.Count != pflist.Count)
                return false;
            int j;
            //	if they are the same size, compare each member.
            for (j = 0; j < pflist.Count; j++)
            {
                //	Lists are sorted, so sequential comparisons must all be true in order for
                if (this[j] != pflist[j])
                    return false;
            }
            return true;
        }
        /// <summary>
        /// Converts a PolygonFlist into a PolygonFarray.
        /// </summary>
        /// <param name="list"></param>
        public PolygonFarray(PolygonFlist list)
        {
            for (int i = 0; i < list.Count; i++)
                this.Add(list[i]);
        }
        public float[] EdgeLengths
        {
            get
            {
                float[] output = new float[this.Count];
                for (int i = 0; i < this.Count; i++)
                {
                    output[i] = this[i].Circumfrence;
                }
                return output;
            }
        }
    }
    [Serializable]
    public class PolygonFlist : CollectionBase
    {
        public PolygonF this[int index]
        {
            get
            {
                return ((PolygonF)List[index]);
            }
            set
            {
                List[index] = value;
            }
        }

        public int Add(PolygonF pf)
        {
            return (List.Add(pf));
        }

        public int IndexOf(PolygonF pf)
        {
            return (List.IndexOf(pf));
        }

        public void Insert(int index, PolygonF pf)
        {
            List.Insert(index, pf);
        }

        public void Remove(PolygonF pf)
        {
            List.Remove(pf);
        }
        public bool Contains(PolygonF pf)
        {
            // If value is not of type PolygonF, this will return false.
            return (List.Contains(pf));
        }

        protected override void OnInsert(int index, object o)
        {
            if (o.GetType() == typeof(PolygonF))
                base.OnInsert(index, o);
            else
                throw new ArgumentException("value must be of type PolygonF.", "value");
        }
        protected override void OnRemove(int index, object o)
        {
            if (o.GetType() == typeof(PolygonF))
                base.OnRemove(index, o);
            else
                throw new ArgumentException("value must be of type PolygonF.", "value");
        }
        protected override void OnSet(int index, object oldValue, object newValue)
        {
            if (newValue.GetType() == typeof(PolygonF))
                base.OnSet(index, oldValue, newValue);
            else
                throw new ArgumentException("newValue must be of type PolygonF.", "newValue");
        }
        protected override void OnValidate(object o)
        {
            if (o.GetType() == typeof(PolygonF))
                base.OnValidate(o);
            else
                throw new ArgumentException("value must be of type PolygonF.");
        }

        /// <summary>
        /// Returns -1 if point not contained, otherwise returns the index of the polygon containing the point.
        /// </summary>
        /// <param name="xx"></param>
        /// <param name="yy"></param>
        /// <returns></returns>
        public void PolygonsContainingPoint(float xx, float yy, PolygonFlist output)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].Pix.PixelIsTagged((int)(xx + 0.5f), (int)(yy + 0.5)))
                    output.Add(this[i]);
        }
        public bool ContainsPoint(float x, float y)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].InPoly(x, y) > 0)
                    return true;
            return false;
        }
        public bool ContainsPoint(int x, int y)
        {
            return ContainsPoint((float)x + 0.5f, (float)y + 0.5f);
        }
        public float[] EdgeLengths
        {
            get
            {
                float[] output = new float[this.Count];
                for (int i = 0; i < this.Count; i++)
                {
                    output[i] = this[i].Circumfrence;
                }
                return output;
            }
        }
    }
    /// <summary>
    /// Holds vertices
    /// </summary>
    [Serializable]
    public class VertexFarray : ArrayList
    {
        public new VertexF this[int index]
        {
            get
            {
                return ((VertexF)base[index]);
            }
            set
            {
                base[index] = value;
            }
        }
        public VertexFarray(ArrayList list)
        {
            for (int i = 0; i < list.Count; i++)
                this.Add(list[i]);
        }
    }
    [Serializable]
    public class CategoryList: CollectionBase
    {
        public CategoryNode this[int index]
        {
            get
            {
                return ((CategoryNode)List[index]);
            }
            set
            {
                List[index] = value;
            }
        }
        public int Add(CategoryNode cn)
        {
            return (List.Add(cn));
        }
        public int IndexOf(CategoryNode cn)
        {
            return (List.IndexOf(cn));
        }
        public void Insert(int index,CategoryNode cn)
        {
            List.Insert(index,cn);
        }
        public void Remove(CategoryNode cn)
        {
            List.Remove(cn);
        }
        public bool Contains(CategoryNode cn)
        {
            // If value is not of type CategoryNode, this will return false.
            return (List.Contains(cn));
        }
        protected override void OnInsert(int index,object o)
        {
            if(o.GetType()!= typeof(CategoryNode))
                throw new ArgumentException("value must be of type CategoryNode.","value");
            base.OnInsert(index,o);
        }
        protected override void OnRemove(int index,object o)
        {
            if(o.GetType()!= typeof(CategoryNode))
                throw new ArgumentException("value must be of type CategoryNode.","value");
            base.OnRemove(index,o);
        }
        protected override void OnSet(int index,object oldValue,object newValue)
        {
            if(newValue.GetType()!= typeof(CategoryNode))
                throw new ArgumentException("newValue must be of type CategoryNode.","newValue");
            base.OnSet(index,oldValue,newValue);
        }
        protected override void OnValidate(object o)
        {
            if(o.GetType()!= typeof(CategoryNode))
                throw new ArgumentException("value must be of type CategoryNode.");
            base.OnValidate(o);
        }
    }
    [Serializable]
    public class ParsedObjectList: CollectionBase
    {
        public ParsedObject this[int index]
        {
            get
            {
                return ((ParsedObject)List[index]);
            }
            set
            {
                List[index] = value;
            }
        }
        public int Add(ParsedObject ob)
        {
            return (List.Add(ob));
        }
        public int IndexOf(ParsedObject ob)
        {
            return (List.IndexOf(ob));
        }
        public void Insert(int index,ParsedObject ob)
        {
            List.Insert(index,ob);
        }
        public void Remove(ParsedObject ob)
        {
            List.Remove(ob);
        }
        public bool Contains(ParsedObject ob)
        {
            // If value is not of type ParsedObject, this will return false.
            return (List.Contains(ob));
        }
        protected override void OnInsert(int index,object o)
        {
            if(o.GetType()!= typeof(ParsedObject))
                throw new ArgumentException("value must be of type ParsedObject.","value");
            base.OnInsert(index,o);
        }
        protected override void OnRemove(int index,object o)
        {
            if(o.GetType()!= typeof(ParsedObject))
                throw new ArgumentException("value must be of type ParsedObject.","value");
            base.OnRemove(index,o);
        }
        protected override void OnSet(int index,object oldValue,object newValue)
        {
            if(newValue.GetType()!= typeof(ParsedObject))
                throw new ArgumentException("newValue must be of type ParsedObject.","newValue");
            base.OnSet(index,oldValue,newValue);
        }
        protected override void OnValidate(object o)
        {
            if(o.GetType()!= typeof(ParsedObject))
                throw new ArgumentException("value must be of type ParsedObject.");
            base.OnValidate(o);
        }
        public void PolygonsContainingPoint(float x,float y,PolygonFlist output)
        {
            for(int i=0;i<this.Count;i++)
                this[i].Polygons.PolygonsContainingPoint(x,y,output);
        }
        /// <summary>
        /// The rectangle which bounds these parsed objects.
        /// </summary>
        public System.Drawing.Rectangle BoundingRect
        {
            get
            {
                if(this.Count==0)
                    return System.Drawing.Rectangle.Empty;
                else
                {
                    System.Drawing.Rectangle rect = this[0].BoundingRect;
                    int top = rect.Top;
                    int left = rect.Left;
                    int bottom = rect.Bottom;
                    int right = rect.Right;
                    for(int i=1;i<this.Count;i++)
                    {
                        rect = this[i].BoundingRect;
                        if(rect.Left < left)
                            left = rect.Left;
                        if(rect.Top < top)
                            top = rect.Top;
                        if(rect.Right > right)
                            right = rect.Right;
                        if(rect.Bottom > bottom)
                            bottom = rect.Bottom;
                    }
                    return System.Drawing.Rectangle.FromLTRB(left, top, right, bottom);
                }
            }
        }
    }
    /// <summary>
    /// Holds occlusion bridges and contains list functionality for occlusion bridges.
    /// </summary>
    [Serializable]
    public class OcclusionBridgeList: CollectionBase
    {
        public OcclusionBridge this[int index]
        {
            get
            {
                return ((OcclusionBridge)List[index]);
            }
            set
            {
                List[index] = value;
            }
        }

        public int Add(OcclusionBridge cn)
        {
            return (List.Add(cn));
        }

        public int IndexOf(OcclusionBridge cn)
        {
            return (List.IndexOf(cn));
        }

        public void Insert(int index,OcclusionBridge cn)
        {
            List.Insert(index,cn);
        }

        public void Remove(OcclusionBridge cn)
        {
            List.Remove(cn);
        }
        public bool Contains(OcclusionBridge cn)
        {
            // If value is not of type OcclusionBridge, this will return false.
            return (List.Contains(cn));
        }

        protected override void OnInsert(int index,object o)
        {
            if(o.GetType()!= typeof(OcclusionBridge))
                throw new ArgumentException("value must be of type OcclusionBridge.","value");
            base.OnInsert(index,o);
        }
        protected override void OnRemove(int index,object o)
        {
            if(o.GetType()!= typeof(OcclusionBridge))
                throw new ArgumentException("value must be of type OcclusionBridge.","value");
            base.OnRemove(index,o);
        }
        protected override void OnSet(int index,object oldValue,object newValue)
        {
            if(newValue.GetType()!= typeof(OcclusionBridge))
                throw new ArgumentException("newValue must be of type OcclusionBridge.","newValue");
            base.OnSet(index,oldValue,newValue);
        }
        protected override void OnValidate(object o)
        {
            if(o.GetType()!= typeof(OcclusionBridge))
                throw new ArgumentException("value must be of type OcclusionBridge.");
            base.OnValidate(o);
        }

    }
    [Serializable]
    public class EdgeGroup: EdgeArray, IComparable
    {
        /// <summary>
        /// Empty constructor.
        /// </summary>
        public EdgeGroup()
        {
            DominantInd=-1;
        }
        /// <summary>
        /// True if there is only a single edge (instead of a pair).
        /// </summary>
        public bool IsSingular
        {
            get
            {
                return this.Count<2;
            }
        }
        /// <summary>
        /// Index into Edges of the dominant edge.  -1 if there is no dominant edge.
        /// </summary>
        public int DominantInd;
        /// <summary>
        /// Gets the currently dominant edge.
        /// </summary>
        public Edge DominantEdge
        {
            get
            {
                if(DominantInd==-1)
                    return null;
                return this[DominantInd];
            }
            set
            {
                DominantInd = this.IndexOf(value);
            }
        }
        #region Sort overrides
        protected static Edge _ed;
        public override void Sort()
        {
            _ed = DominantEdge;
            base.Sort();
            if(_ed!=null)
                DominantEdge = _ed;
        }
        public override void Sort(int index,int count,IComparer comparer)
        {
            _ed = DominantEdge;
            base.Sort(index,count,comparer);
            if(_ed!=null)
                DominantEdge = _ed;
        }
        public override void Sort(IComparer comparer)
        {
            _ed = DominantEdge;
            base.Sort(comparer);
            if(_ed!=null)
                DominantEdge = _ed;
        }

        #endregion
        public bool ContentsAreSameAs(EdgeGroup obj)
        {
            if(IsSingular)
            {
                if(obj.IsSingular)
                    return this[0].SameEdgeAs(obj[0]);
                else
                    return false;
            }
            else
            {
                if(this.Count!=obj.Count || DominantEdge!=obj.DominantEdge)
                    return false;
                this.Sort();
                obj.Sort();
                for(int i=0;i<this.Count;i++)
                    if(!this[i].SameEdgeAs(obj[i]))
                        return false;
                return true;
            }
        }
        /// <summary>
        /// Finds the first edge owned by a polygon other than pf.  An EdgeGroup should only contain two polygons.
        /// </summary>
        /// <param name="pf">A PolygonF</param>
        /// <returns>The edge owned by a PolygonF besides pf.</returns>
        public Edge EdgeOfAnotherPoly(PolygonF pf)
        {
            for(int i=0;i<this.Count;i++)
                if(this[i].Owner != pf)
                    return this[i];
            return null;
        }
        /// <summary>
        /// Gets the member edge that is part of the specified polygon.  Returns null if the polygon
        /// does not own a member.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public Edge EdgeOwnedBy(PolygonF poly)
        {
            for(int i=0;i<this.Count;i++)
                if(this[i].Owner==poly)
                    return this[i];
            return null;
        }
        private int _h1,_h2;
        public int CompareTo(object obj)
        {
            _h1 = this.GetHashCode();
            _h2 = obj.GetHashCode();
            if(_h1<_h2)
                return -1;
            if(_h1>_h2)
                return 1;
            return 0;
        }
    }
    [Serializable]
    public class EdgeArray: ArrayList
    {
        public new Edge this[int index]
        {
            get
            {
                return ((Edge)base[index]);
            }
            set
            {
                base[index] = value;
            }
        }
        /// <summary>
        /// Returns the index of a paired twin of the argument, if it exists in the ArrayList, -1 otherwise.
        /// </summary>
        /// <param name="fe"></param>
        /// <returns></returns>
        public int FindTwinOf(Edge fe)
        {
            if(fe==null)
                return -1;
            for(int i=0;i<this.Count;i++)
            {
                if(fe.IsTwinOf(this[i]))
                    return i;
            }
            return -1;
        }
        /// <summary>
        /// Finds the index an edge in this ArrayList with the same parameter values as fe,
        /// -1 if none found.
        /// </summary>
        /// <param name="fe"></param>
        /// <returns></returns>
        public int FindSameEdgeAs(Edge fe)
        {
            if(fe==null)
                return -1;
            for(int i=0;i<this.Count;i++)
                if(fe.SameEdgeAs(this[i]))
                    return i;
            return -1;
        }
    }
    [Serializable]
    public class EdgeGroupArray: ArrayList,IComparable
    {
        public new EdgeGroup this[int index]
        {
            get
            {
                return ((EdgeGroup)base[index]);
            }
            set
            {
                base[index] = value;
            }
        }
        /// <summary>
        /// Returns the index of the only (or first) EdgeGroup that owns the VertexF.
        /// </summary>
        /// <param name="vf"></param>
        /// <returns>Returns the index of the only (or first) EdgeGroup that owns the VertexF.</returns>
        public int UniqueVertexOwner(VertexF vf,VertexF disambiguator)
        {
            if(this.Count==0)
                return -1;
            if(this.Count==1 && this[0][0].IsFullEnclosure)
                return 0;
            int i,ind,bInd,eInd,indDis;
            Edge fe;

            for(i=0;i<this.Count;i++)
            {
                fe = this[i][0];
                //	Compute the index
                ind = fe.Owner.IndexOf(vf);
                indDis = -1;
                //	Update the index if necessary.
                if(ind<0 || ind>fe.Owner.Count || fe.Owner[ind]!=vf)
                    ind = fe.Owner.IndexOf(vf);
                if(ind>=0)
                {
                    bInd = fe.Owner.IndexOf(fe.Begin);
                    eInd = fe.Owner.IndexOf(fe.End);
                    //	If the index is on a junction between edges, the disambiguator
                    //	might help is figure out what's up.
                    if(disambiguator!=null && (bInd==ind || eInd==ind))
                    {
                        indDis = fe.Owner.IndexOf(disambiguator);
                        if(bInd==indDis || eInd==indDis)
                            return i;
                        if(fe.OwnsIndex(indDis))
                            return i;
                    }
                    //	The disambiguator has no relevance, just look for the edge containing vf inside.
                    if((disambiguator==null || indDis < 0) && eInd>bInd && ind>=bInd && ind<=eInd)
                        return i;
                    else if((disambiguator==null || indDis < 0) && eInd<bInd && (ind<=eInd||ind>=bInd))
                        return i;
                }
            }
            return -1;
        }
        /// <summary>
        /// Removes the elements from this EdgeGroupArray which are the same as
        /// any element of the argument "fepa".  Similarities are computed via
        /// EdgeGroup.ContentsAreSameAs(EdgeGroup).
        /// </summary>
        /// <param name="fepa"></param>
        public void EliminateSimilaritiesFrom(EdgeGroupArray fepa)
        {
            int ct = 0;
            int i;
            while(ct < this.Count)
            {
                for(i=0;i<fepa.Count;i++)
                {
                    if(fepa[i].ContentsAreSameAs(this[ct]))
                    {
                        this.RemoveAt(ct--);
                        break;
                    }
                }
                ct++;
            }
        }
        /// <summary>
        /// Hashcode comparison for sorting.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int CompareTo(object obj)
        {
            int thisHash = this.GetHashCode();
            int thatHash = obj.GetHashCode();
            if(thisHash > thatHash)
                return 1;
            if(thisHash < thatHash)
                return -1;
            return 0;
        }
    }
}
